﻿function ECommerceViewModel(urls) {

    var self = this;

    var context = new ECommerceContext(urls);

    var spaRuntime = context.spaRuntime;

    var screen = ko.observable('');

    var mainRoute = new SpaRoute('root', '/').addExecute(function (ev, args, phash) {
        screen('products');
    });

    var productsRoute = new SpaRoute('products', 'products').addExecute(function (ev, args, phash) {
        screen('products');
    });

    var productsByTagRoute = new SpaRoute('productsByTag', 'products/tags/{tag}').addExecute(function (ev, args, phash) {
        screen('products');
    });

    var productSearchRoute = new SpaRoute('productsSearch', 'products/search/{term}').addExecute(function (ev, args, phash) {
        screen('products');
    });


    var productInfoRoute = new SpaRoute('product', 'product/{id}').addExecute(function (ev, args, phash) {
        screen('product');
    });

    var productEditRoute = new SpaRoute('productEdit', 'product/{id}/edit').addExecute(function (ev, args, phash) {
        screen('productDetails');
    });

    var productReviewEditRoute = new SpaRoute('productReviewEdit', 'product/{id}/reviews/{reviewId}').addExecute(function (ev, args, phash) {
        screen('reviewDetails');
    });

    var productReviewNewRoute = new SpaRoute('productReviewNew', 'product/{id}/reviews/').addExecute(function (ev, args, phash) {
        screen('reviewDetails');
    });

    var productNewRoute = new SpaRoute('productNew', 'product/new').addExecute(function (ev, args, phash) {
        screen('productDetails');
    });

    var cartRoute = new SpaRoute('cart', 'cart').addExecute(function (ev, args, phash) {
        screen('cart');
    });

    var ordersRoute = new SpaRoute('orders', 'orders').addExecute(function (ev, args, phash) {
        screen('orders');
    });

    var orderDetailsRoute = new SpaRoute('order', 'orders/{orderId}').addExecute(function (ev, args, phash) {
        screen('order');
    });

    var thankYouRoute = new SpaRoute('thankyou', 'thankyou').addExecute(function (ev, args, phash) {
        screen('thankyou');
    });

    spaRuntime.addRoutes(mainRoute,
        productsRoute, productsByTagRoute, productSearchRoute, productNewRoute, productInfoRoute, productEditRoute,
        productReviewEditRoute, productReviewNewRoute,
        cartRoute, thankYouRoute,
        ordersRoute, orderDetailsRoute);

    var products = new ECommerceProductsViewModel(context);
    var product = new ECommerceProductViewModel(context);
    var productDetails = new ECommerceProductDetailsViewModel(context);
    var reviewDetails = new ECommerceProductReviewDetailsViewModel(context);
    var cart = new ECommerceCartViewModel(context);
    var recent = new ECommerceRecentViewModel(context);
    var signInView = new SignInView(context);

    var ordersView = new ECommerceOrdersViewModel(context);
    var orderView = new ECommerceOrderViewModel(context);

    function reloadTags() {
        var api = context.api();
        api.products.getTags(function (res) {
            tags.items(res);
        });
    }

    function search() {
        var term = context.searchTerm();
        window.location.hash = productSearchRoute.formatHash({
            term: term
        });
    }

    productInfoRoute.addExecute(function (ev, args, phash) {
        product.showFor({
            id: args.id,
            pageNumber: args.pageNumber,
            pageSize: args.pageSize
        });
    });

    productEditRoute.addExecute(function (ev, args, phash) {
        productDetails.showFor(args.id);
    });

    productReviewEditRoute.addExecute(function (ev, args) {
        reviewDetails.showFor(args.id, args.reviewId);
    });

    productReviewNewRoute.addExecute(function (ev, args) {
        reviewDetails.showForNew(args.id);
    });

    productNewRoute.addExecute(function (ev, args, phash) {
        productDetails.showForNew();
    });

    cart.reload();
    cartRoute.addExecute(function () {
        cart.reload();
    });

    mainRoute.addExecute(function (ev, args) {
        products.showAll({
            pageNumber: args.pageNumber,
            pageSize: args.pageSize
        });
    });

    productsRoute.addExecute(function (ev, args) {
        products.showAll({
            pageNumber: args.pageNumber,
            pageSize: args.pageSize
        });
    });
    productSearchRoute.addExecute(function (ev, args) {
        products.search(context.searchTerm(), {
            pageNumber: args.pageNumber,
            pageSize: args.pageSize
        });
    });
    productsByTagRoute.addExecute(function (ev, args) {
        products.searchTag(args.tag, {
            pageNumber: args.pageNumber,
            pageSize: args.pageSize
        });
    });

    ordersRoute.addExecute(function () {
        ordersView.reload();
    });

    orderDetailsRoute.addExecute(function (ev, args, phash) {
        orderView.showFor(args.orderId);
    });

    var tags = new TagsList(context);

    reloadTags();

    productDetails.addOnSuccess(function () {
        reloadTags();
    });

    spaRuntime.check();

    self.context = context;
    self.screen = screen;
    self.products = products;
    self.product = product;
    self.productDetails = productDetails;
    self.reviewDetails = reviewDetails;
    self.cart = cart;
    self.recent = recent;
    self.ordersView = ordersView;
    self.orderView = orderView;
    self.signInView = signInView;
    self.search = search;
    self.tags = tags;
}

function ECommerceContext(urls) {

    var self = this;

    var spaRuntime = new SpaRuntime();

    var userEmail = ko.observable(window.localStorage.getItem('account'));

    var api = ko.computed(function () {
        return new ECommerceApi(urls, userEmail());
    });

    var products = ko.observableArray([]);

    var recentProducts = ko.observableArray([]);

    var productsByTag = ko.observableArray([]);

    var cart = ko.observable(new ECommerceCart());

    var searchTerm = ko.observable('');

    function addToCart(product) {
        var c = cart();
        if (c) {
            var cartItem = c.findByProduct(product.id());
            if (!cartItem) {
                cartItem = new ECommerceCartItem();
                cartItem.fromProduct(product);
                c.items.push(cartItem);
            }
            cartItem.count(cartItem.count() + 1);
            api().cart.postItem(cartItem.getInfo());
        }
    }

    function findProductById(id) {
        var array = products();
        for (var i = 0; i < array.length; i++) {
            var product = array[i];
            if (product.id() == id) return product;
        }
        return null;
    }

    function getLastVisitedProduct() {
        var recent = recentProducts();
        if (recent.length > 0)
            return recent[0].id();

        return null;
    }
    
    function addVisitedProduct(product) {
        var res = [];
        res.push(product);

        var pid = product.id();

        var recent = recentProducts();
        for (var i = 0; i < recent.length; i++) {
            var p = recent[i];
            if (p.id() != pid) {
                res.push(p);
                if (res.length >= 10) break;
            }
        }
        recentProducts(res);
    }

    self.products = products;
    self.recentProducts = recentProducts;
    self.productsByTag = productsByTag;
    self.cart = cart;
    self.findProductById = findProductById;
    self.addToCart = addToCart;
    self.spaRuntime = spaRuntime;
    self.api = api;
    self.userEmail = userEmail;
    self.searchTerm = searchTerm;
    self.getLastVisitedProduct = getLastVisitedProduct;
    self.addVisitedProduct = addVisitedProduct;
}

function TagsList(context) {

    var self = this;

    var productsByTag = context.spaRuntime.findRouteByName('productsByTag');

    var items = ko.observableArray([]);

    function getByTagUrl(tag) {
        return productsByTag.formatHash({
            tag: tag
        });
    }

    self.items = items;
    self.getByTagUrl = getByTagUrl;

}